{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 场景三：面向文档的对话机器人"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pulling manifest\n",
      "pulling 8359bebea988... 100% |██████████████████| (7.4/7.4 GB, 63 TB/s)        \n",
      "pulling 65c6ec5c6ff0... 100% |████████████████████| (45/45 B, 2.2 MB/s)        \n",
      "pulling dd36891f03a0... 100% |████████████████████| (31/31 B, 1.2 MB/s)        \n",
      "pulling f94f529485e6... 100% |███████████████████| (382/382 B, 22 MB/s)        \n",
      "verifying sha256 digest\n",
      "writing manifest\n",
      "removing any unused layers\n",
      "success\n"
     ]
    }
   ],
   "source": [
    "!ollama pull llama2-chinese:13b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install langchain langchain-core langchain-community\n",
    "%pip install faiss-cpu networkx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ReAct：SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS，是一篇由Department of Computer Science, Princeton University和Google Research的Brain team合作在ICLR 2023发表的研究论文。ReAct旨在探索LLMs用于生成任务解释轨迹和任务特定动作的方法，以实现更加优化的解决问题之间的交织关系。该项目使用了简单的Wikipedia API来并行地生成人类可读的解释轨迹和任务轨迹，从而获得更好的探索性能和解决问题效果。'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "from langchain_core.prompts import ChatPromptTemplate, PromptTemplate, format_document\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n",
    "from langchain_community.chat_models import ChatOllama\n",
    "from langchain_community.embeddings import OllamaEmbeddings\n",
    "from langchain_community.vectorstores.faiss import FAISS\n",
    "from langchain_community.document_loaders import ArxivLoader\n",
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "\n",
    "# 加载 arXiv 上的论文《ReAct: Synergizing Reasoning and Acting in Language Models》\n",
    "loader = ArxivLoader(query=\"2210.03629\", load_max_docs=1)\n",
    "docs = loader.load()\n",
    "\n",
    "# 把文本分割成 200 字一组的切片\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)\n",
    "chunks = text_splitter.split_documents(docs)\n",
    "\n",
    "# 构建 FAISS 向量存储和对应的 retriever\n",
    "vs = FAISS.from_documents(chunks[:10], OllamaEmbeddings(model=\"llama2-chinese:13b\"))\n",
    "# vs.similarity_search(\"What is ReAct\")\n",
    "retriever = vs.as_retriever()\n",
    "\n",
    "# 构建 Document 转文本段落的工具函数\n",
    "DEFAULT_DOCUMENT_PROMPT = PromptTemplate.from_template(template=\"{page_content}\")\n",
    "def _combine_documents(\n",
    "    docs, document_prompt=DEFAULT_DOCUMENT_PROMPT, document_separator=\"\\n\\n\"\n",
    "):\n",
    "    doc_strings = [format_document(doc, document_prompt) for doc in docs]\n",
    "    return document_separator.join(doc_strings)\n",
    "\n",
    "# 准备 Model I/O 三元组\n",
    "template = \"\"\"Answer the question based only on the following context:\n",
    "{context}\n",
    "\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(template)\n",
    "model = ChatOllama(model=\"llama2-chinese:13b\")\n",
    "\n",
    "# 构建 RAG 链\n",
    "chain = (\n",
    "    {\n",
    "        \"context\": retriever | _combine_documents,\n",
    "        \"question\": RunnablePassthrough()\n",
    "    }\n",
    "    | prompt\n",
    "    | model\n",
    "    | StrOutputParser()\n",
    ")\n",
    "chain.invoke(\"什么是 ReAct？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'history': 'On LangChain: LangChain application development framework for large language models.'}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_community.llms.ollama import Ollama\n",
    "from langchain.memory import ConversationKGMemory\n",
    "\n",
    "llm = Ollama(model=\"llama2-chinese:13b\")\n",
    "memory = ConversationKGMemory(llm=llm)\n",
    "memory.save_context({\"input\": \"LangChain 是什么\"}, {\"output\": \"LangChain 是一个大语言模型的应用开发框架，目前有 Python 和 JavaScript SDK\"})\n",
    "memory.save_context({\"input\": \"Ollama 又是什么\"}, {\"output\": \"Ollama 是一个跨平台的运行大语言模型的工具软件，目前可以在 Linux 和 macOS 平台上运行\"})\n",
    "\n",
    "memory.load_memory_variables({\"input\": \"LangChain 是啥？\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
